package main

import (
	"fmt"
	"reflect"
)

// ========== 核心： injector ==========
type injector struct {
	values map[reflect.Type]reflect.Value // 类型 -> 值
}

func New() *injector {
	return &injector{values: make(map[reflect.Type]reflect.Value)}
}

// Map ：按值的真实类型存
func (i *injector) Map(val interface{}) {
	i.values[reflect.TypeOf(val)] = reflect.ValueOf(val)
}

// MapTo ：按指定接口类型存
func (i *injector) MapTo(val interface{}, ifacePtr interface{}) {
	// 取出接口类型
	ifaceType := reflect.TypeOf(ifacePtr).Elem()
	i.values[ifaceType] = reflect.ValueOf(val)
}

// Invoke ：自动填参 -> 调用
func (i *injector) Invoke(fn interface{}) ([]reflect.Value, error) {
	fnValue := reflect.ValueOf(fn)
	fnType := fnValue.Type()
	if fnType.Kind() != reflect.Func {
		return nil, fmt.Errorf("need func, got %v", fnType.Kind())
	}
	// 构造入参
	in := make([]reflect.Value, fnType.NumIn())
	for j := 0; j < fnType.NumIn(); j++ {
		argType := fnType.In(j)
		val, ok := i.values[argType]
		if !ok {
			return nil, fmt.Errorf("value not found for type %v", argType)
		}
		in[j] = val
	}
	// 反射调用
	return fnValue.Call(in), nil
}

// ========== 使用示例 ==========
type S1 interface{}
type S2 interface{}

func Format(name string, company S1, level S2, age int) {
	fmt.Printf("name=%s, company=%s, level=%s, age=%d\n", name, company, level, age)
}

func main() {
	inj := New()
	// 1. 往仓库里贴标签存值
	inj.Map("tom")                   // 键=string
	inj.MapTo("tencent", (*S1)(nil)) // 键=S1 接口
	inj.MapTo("T4", (*S2)(nil))      // 键=S2 接口
	inj.Map(23)                      // 键=int

	// 2. 让仓库帮咱们调函数
	if _, err := inj.Invoke(Format); err != nil {
		fmt.Println("Invoke error:", err)
	}
}
